/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package deatax.display;

import deatax.ResourceLoader;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Caroline
 */
public class ModelLoader {

    protected static ModelLoader defaultLoader = new ModelLoader();

    public static Model loadModel(String model) throws FileNotFoundException {
//        ObjectFile objFileloader = new ObjectFile(ObjectFile.RESIZE);
//        System.out.println(model);
//        Scene s = objFileloader.load(Main.class.getResource(model));
//        for (int i = 0; i < s.getSceneGroup().numChildren(); i++) {
//            Model m = new Model();
//            if (s.getSceneGroup().getChild(i) instanceof Shape3D) {
//                Shape3D shape = (Shape3D) s.getSceneGroup().getChild(i);
//                int n = shape.numGeometries();
//                for (int j = 0; j < n; j++) {
//                    Geometry g = shape.getGeometry(i);
//                    if (g instanceof TriangleArray) {
//                        TriangleArray tri = (TriangleArray) g;
//                        m.addPart(tri.getVertexCount(), tri.getInterleavedVertices(), null);
//                        float[] data = tri.getInterleavedVertices();
//                        for (int h = 0; h < data.length; h+=WORD) {
//                        System.out.println(String.format("(%f,%f) - (%f,%f,%f) - (%f,%f,%f)",
//                                data[h],data[h+1]
//                                ,data[h+2],data[h+3],data[h+4]
//                                ,data[h+5],data[h+6],data[h+7]));
//                        }
//                    }
//                }
//                return m;
//            }
//        }
//        return null;
        try {
//            loadModel("markers/base.obj");
//                System.out.println("Loading model: " + model);
            //InputStream fis = Main.class.getResourceAsStream(model);
//            InputStream fis = new FileInputStream(model);
//            System.out.println(fis);
            Model m = defaultLoader.readStream(ResourceLoader.loadStream(model));
//            System.out.println("Done loading" + m);
            return m;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    public static void main(String args[]) {
        try {
//            loadModel("markers/base.obj");

            //InputStream fis = Marker.class.getResourceAsStream("base.obj");
            InputStream fis = new FileInputStream("markers/base.obj");
            ModelLoader ml = new ModelLoader();
            Model m = ml.readStream(fis);
        } catch (Exception ex) {
            Logger.getLogger(ModelLoader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    static int WORD = 8; // tx, ty, nx, ny, nz, vx, vy, vz
    static int BUFFER_SIZE = 128;

    public Model readStream(InputStream is) {
        BufferedInputStream bis = new BufferedInputStream(is);

        Scanner s = new Scanner(bis);

        FloatBuffer vertices = new FloatBuffer(3);
        FloatBuffer normals = new FloatBuffer(3);
        FloatBuffer textureCoords = new FloatBuffer(2);
        FloatBuffer modelData = new FloatBuffer(8);

        String[] split;

        Model m = new Model();

        String line = "";
        int face_count = 0;
        while (s.hasNextLine()) {
            line = s.nextLine();
            split = line.split(" ");
            if (split[0].equals("usemtl")) {
                if (!modelData.isEmpty()) {
                    m.addPart(modelData.index, modelData.toArray(), null);
                    modelData.clear();
                }
            } else if (split[0].equals("v")) {
                vertices.add(Float.parseFloat(split[1]), Float.parseFloat(split[2]), Float.parseFloat(split[3]));
            } else if (split[0].equals("vt")) {
                textureCoords.add(Float.parseFloat(split[1]), Float.parseFloat(split[2]));
            } else if (split[0].equals("vn")) {
                normals.add(Float.parseFloat(split[1]), Float.parseFloat(split[2]), Float.parseFloat(split[3]));
            } else if (split[0].equals("f")) {
                String[] face;
                for (int i = 1; i < split.length; i++) {
                    face_count++;
                    face = split[i].split("/");
//                        System.out.println("---------------------------");
//                        System.out.println(split[i]);
                    textureCoords.copyTo(modelData, Integer.parseInt(face[1]) - 1);
                    normals.copyTo(modelData, Integer.parseInt(face[2]) - 1);
                    vertices.copyTo(modelData, Integer.parseInt(face[0]) - 1);
                }
            }

        }
        System.out.println("Facecount: " + face_count * 8);
        if (!modelData.isEmpty()) {
            m.addPart(modelData.index, modelData.toArray(), null);
            modelData.clear();
        } else {
            return null;
        }

        return m;
    }

    private class FloatBuffer {

        float[] current;
        ArrayList<float[]> stack = new ArrayList<float[]>();
        int index = 0;
        int word;

        public FloatBuffer(int word) {
            this.word = word;
            clear();
        }

        private void checkFull() {
            if (index >= BUFFER_SIZE * word) {
                current = new float[BUFFER_SIZE * word];
                stack.add(current);
                index = 0;
            }
        }

        public void add(float f) {
            checkFull();
            current[index++] = f;
        }

        public void add(float f, float f2) {
            checkFull();
            current[index++] = f;
            current[index++] = f2;
        }

        public void add(float f, float f2, float f3) {
            checkFull();
            current[index++] = f;
            current[index++] = f2;
            current[index++] = f3;
        }

        public void copyTo(FloatBuffer dst, int src_index) {
            for (int i = 0; i < word; i++) {
                dst.add(stack.get((src_index * word + i) / (BUFFER_SIZE * word))[(src_index * word + i) % (BUFFER_SIZE * word)]);
//                System.out.println("["+((src_index * word + i) / (BUFFER_SIZE*word))+"]["+(src_index * word + i) % (BUFFER_SIZE* word)+"]"+stack.get((src_index * word + i) / (BUFFER_SIZE*word))[(src_index * word + i) % (BUFFER_SIZE* word)]);
            }
        }

        public boolean isEmpty() {
            return index == 0 && stack.size() == 1;
        }

        public float[] toArray() {
            float[] finBuffer = new float[(stack.size()-1)*BUFFER_SIZE*word+index];
//            System.out.println("vertex count: " + index);
            for (int i = 0; i < stack.size(); i++) {
//                System.out.println("From : " + i / BUFFER_SIZE + " - " + (index / word - BUFFER_SIZE * i > BUFFER_SIZE ? BUFFER_SIZE * word : (index - BUFFER_SIZE * i * word)) + " To: " + i * word * BUFFER_SIZE + "(" + i + ")");
                if (i != stack.size() - 1) {
//                    System.out.println("Copy from : 0 - " + (BUFFER_SIZE * word) + "to : " + i * word * BUFFER_SIZE);
                    System.arraycopy(stack.get(i), 0, finBuffer, i * word * BUFFER_SIZE, BUFFER_SIZE * word);
                } else {
//                    System.out.println("Copy from : 0 - " + (index) + " to : " + i * word * BUFFER_SIZE + " --- " + finBuffer.length);
                    System.arraycopy(stack.get(i), 0, finBuffer, i * word * BUFFER_SIZE, index);
                }
            }
//            for (int i = 0; i < finBuffer.length; i += WORD) {
//                System.out.println(String.format("(%f,%f) - (%f,%f,%f) - (%f,%f,%f)",
//                        finBuffer[i], finBuffer[i + 1],
//                        finBuffer[i + 2], finBuffer[i + 3], finBuffer[i + 4],
//                        finBuffer[i + 5], finBuffer[i + 6], finBuffer[i + 7]));
//            }
            return finBuffer;
        }

        public void clear() {
            index = 0;
            stack.clear();
            current = new float[BUFFER_SIZE * word];
            stack.add(current);
        }
    }

    public static float[] swapBuffers(ArrayList<float[]> buffers, int index) {
        if (buffers.size() < index + 1) {
            buffers.add(new float[BUFFER_SIZE * WORD]);
        }

        return buffers.get(index);
    }
}
